package com.yoso.starter.boot.util.file;


import cn.hutool.core.io.FileUtil;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import com.yoso.starter.boot.util.file.param.WatermarkDO;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.officeDocument.x2006.sharedTypes.STTrueFalse;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.core.io.ClassPathResource;

import java.awt.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.stream.Stream;

/**
 * word文件水印处理
 *
 * @author shizejin
 * @date 2024/12/02
 */
@Slf4j
public class WordWatermarkHandler extends AbstractWatermarkHandler {

    //一个字平均长度，单位pt，用于：计算文本占用的长度（文本总个数*单字长度）
    private static int widthPerWord = 36;
    // 与顶部的间距
    private static float styleTop = 0;
    // 文本旋转角度
    private static final double styleRotation = -30;
    // 一行水印重复空格次数
    private static final int markSpace = 8;
    // 一行水印重复水印文字次数
    private static final int markNum = 5;
    //水印字体样式
    private static final String fontFamily = "宋体";


    @SneakyThrows
    public static void main(String[] args) {
        WordWatermarkHandler pdfWatermarkHandler = new WordWatermarkHandler();
        WatermarkDO watermarkDO = new WatermarkDO();
        watermarkDO.setWatermark("仅用于光大理财账户管理模块");
//        watermarkDO.setWatermark("禁止抄袭");
        watermarkDO.setFontSize(20);
        watermarkDO.setSrcPath("D:\\yoso\\dev\\temp\\1.docx");
        watermarkDO.setDestPath("D:\\yoso\\dev\\temp\\2.docx");
        pdfWatermarkHandler.appendWatermark(watermarkDO);
    }

    /**
     * 给文件添加水印
     *
     * @param watermarkDO
     * @author shizejin
     * @date 2024/11/26
     */
    @Override
    public void appendWatermark(WatermarkDO watermarkDO) throws IOException {
        XWPFDocument xwpfDocument = new XWPFDocument(FileUtil.getInputStream(watermarkDO.getSrcPath()));
        waterMarkDocXDocument(xwpfDocument, watermarkDO.getWatermark(),
                "808080", watermarkDO.getFontSize(), 30);
        // 保存修改后的文档
        try (OutputStream fos = FileUtil.getOutputStream(watermarkDO.getDestPath())) {
            xwpfDocument.write(fos);
        }
    }


    /**
     * 给docx文档添加水印
     * 此方法可以单独使用
     *
     * @param doc
     * @param customText
     */
    public static void waterMarkDocXDocument(XWPFDocument doc, String customText, String fontColor, int fontSize, float opacity) {
        widthPerWord = fontSize;
        fontColor = ColorTransparency(fontColor, opacity);
        //水印行高
        float wordHight = 400f;
        // 水印文字之间使用8个空格分隔
        customText = repeatString(" ", markSpace) + customText;
        // 一行水印重复水印文字次数
        customText = repeatString(customText, markNum);
        //补充水印结尾空格
        customText = customText + repeatString(" ", markSpace);
        // 把整页都打上水印
        for (int lineIndex = -5; lineIndex < 20; lineIndex++) {
            styleTop = wordHight * lineIndex;
            // 添加默认页眉水印
            waterMarkDocXDocument_0(doc, customText, fontColor, HeaderFooterType.DEFAULT);
            // 添加第一页页眉水印
            waterMarkDocXDocument_0(doc, customText, fontColor, HeaderFooterType.FIRST);
        }
    }

    /**
     * 给docx文档添加水印
     *
     * @param doc        需要被处理的docx文档对象
     * @param customText 需要添加的水印文字
     */
    public static void waterMarkDocXDocument_0(XWPFDocument doc, String customText, String fontColor, HeaderFooterType headerFooterType) {
        // 如果之前已经创建过 DEFAULT 的Header，将会复用
        XWPFHeader header = doc.createHeader(headerFooterType);
        int size = header.getParagraphs().size();
        if (size == 0) {
            header.createParagraph();
        }
        CTP ctp = header.getParagraphArray(0).getCTP();
        byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
        byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
        ctp.setRsidP(rsidr);
        ctp.setRsidRDefault(rsidrdefault);
        CTPPr ppr = ctp.addNewPPr();
        ppr.addNewPStyle().setVal("Header");
        // 开始加水印
        CTR ctr = ctp.addNewR();
        CTRPr ctrpr = ctr.addNewRPr();
        ctrpr.addNewNoProof();
        CTGroup group = CTGroup.Factory.newInstance();
        CTShapetype shapetype = group.addNewShapetype();
        CTTextPath shapeTypeTextPath = shapetype.addNewTextpath();
        shapeTypeTextPath.setOn(STTrueFalse.T);
        shapeTypeTextPath.setFitshape(STTrueFalse.T);
        CTLock lock = shapetype.addNewLock();
        lock.setExt(STExt.VIEW);
        CTShape shape = group.addNewShape();
        shape.setId("PowerPlusWaterMarkObject");
        shape.setSpid("_x0000_s102");
        shape.setType("#_x0000_t136");
        // 设置形状样式（旋转，位置，相对路径等参数）
        shape.setFillcolor(fontColor);
        shape.setStyle(getShapeStyle(customText));
        // 字体设置为实心
        shape.setStroked(STTrueFalse.FALSE);
        // 绘制文本的路径
        CTTextPath shapeTextPath = shape.addNewTextpath();
        // 设置文本类型
        shapeTextPath.setStyle("font-family:" + fontFamily);
        shapeTextPath.setString(customText);
        CTPicture pict = ctr.addNewPict();
        pict.set(group);
    }

    /**
     * 将指定的字符串重复repeats次.
     */
    private static String repeatString(String pattern, int repeats) {
        StringBuilder buffer = new StringBuilder(pattern.length() * repeats);
        Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append);
        return new String(buffer);
    }

    /**
     * 根据透明度改变颜色，透明度为100时为白色，0时为初始颜色
     *
     * @param fontColor 颜色
     * @param opacity   透明度（取值：0-100）
     * @return
     */
    public static String ColorTransparency(String fontColor, float opacity) {
        Color fontColorValue = Color.decode("#" + fontColor);
        int red = (int) ((255 - fontColorValue.getRed()) * (opacity / 100.0f));
        int green = (int) ((255 - fontColorValue.getGreen()) * (opacity / 100.0f));
        int blue = (int) ((255 - fontColorValue.getBlue()) * (opacity / 100.0f));
        Color newColor = new Color(255 - red, 255 - green, 255 - blue);
        String newColorStr = "#" + Integer.toHexString(newColor.getRGB()).substring(2);
        return newColorStr;
    }

    /**
     * 构建Shape的样式参数
     *
     * @param customText
     * @return
     */
    private static String getShapeStyle(String customText) {
        StringBuilder sb = new StringBuilder();
        // 文本path绘制的定位方式
        sb.append("position: ").append("absolute");
        // 计算文本占用的长度（文本总个数*单字长度）
        sb.append(";width: ").append(customText.length() * widthPerWord).append("pt");
        // 字体高度
        sb.append(";height: ").append(2 * widthPerWord + "pt");
        sb.append(";z-index: ").append("-251654144");
        sb.append(";mso-wrap-edited: ").append("f");
        // 设置水印的间隔，这是一个大坑，不能用top,必须要margin-top。
        sb.append(";margin-top: ").append(styleTop);
        sb.append(";mso-position-horizontal-relative: ").append("page");
        sb.append(";mso-position-vertical-relative: ").append("page");
        sb.append(";mso-position-vertical: ").append("left");
        sb.append(";mso-position-horizontal: ").append("center");
        sb.append(";rotation: ").append(styleRotation);
        return sb.toString();
    }
}
